{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Two neurons\n",
    "\n",
    "This demo shows how to construct and manipulate\n",
    "a complementary pair of neurons.\n",
    "\n",
    "These are leaky integrate-and-fire (LIF) neurons.\n",
    "The neuron tuning properties have been selected\n",
    "so there is one 'on' and one 'off' neuron.\n",
    "\n",
    "One neuron will increase for positive input,\n",
    "and the other will decrease.\n",
    "This can be thought of as the simplest population\n",
    "that is able to give a reasonable representation of a scalar value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "import nengo\n",
    "from nengo.dists import Uniform\n",
    "from nengo.utils.matplotlib import rasterplot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 1: Create the neurons"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = nengo.Network(label='Two Neurons')\n",
    "with model:\n",
    "    neurons = nengo.Ensemble(\n",
    "        2, dimensions=1,  # Representing a scalar\n",
    "        intercepts=Uniform(-.5, -.5),  # Set the intercepts at .5\n",
    "        max_rates=Uniform(100, 100),  # Set the max firing rate at 100hz\n",
    "        encoders=[[1], [-1]])  # One 'on' and one 'off' neuron"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 2: Create input for the model\n",
    "\n",
    "Create an input node generating a sine wave."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with model:\n",
    "    sin = nengo.Node(lambda t: np.sin(8 * t))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 3: Connect the network elements"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with model:\n",
    "    nengo.Connection(sin, neurons, synapse=0.01)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 4: Probe outputs\n",
    "\n",
    "Anything that is probed will collect the data it produces over time,\n",
    "allowing us to analyze and visualize it later."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with model:\n",
    "    sin_probe = nengo.Probe(sin)  # The original input\n",
    "    spikes = nengo.Probe(neurons.neurons)  # Raw spikes from each neuron\n",
    "    # Subthreshold soma voltages of the neurons\n",
    "    voltage = nengo.Probe(neurons.neurons, 'voltage')\n",
    "    # Spikes filtered by a 10ms post-synaptic filter\n",
    "    filtered = nengo.Probe(neurons, synapse=0.01)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 5: Run the model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with nengo.Simulator(model) as sim:  # Create a simulator\n",
    "    sim.run(1)  # Run it for 1 second"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 6: Plot the results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "t = sim.trange()\n",
    "\n",
    "# Plot the decoded output of the ensemble\n",
    "plt.figure()\n",
    "plt.plot(t, sim.data[filtered])\n",
    "plt.plot(t, sim.data[sin_probe])\n",
    "plt.xlim(0, 1)\n",
    "\n",
    "# Plot the spiking output of the ensemble\n",
    "plt.figure(figsize=(10, 8))\n",
    "plt.subplot(2, 2, 1)\n",
    "rasterplot(t, sim.data[spikes], colors=[(1, 0, 0), (0, 0, 0)])\n",
    "plt.yticks((1, 2), (\"On neuron\", \"Off neuron\"))\n",
    "plt.ylim(2.5, 0.5)\n",
    "\n",
    "# Plot the soma voltages of the neurons\n",
    "plt.subplot(2, 2, 2)\n",
    "plt.plot(t, sim.data[voltage][:, 0] + 1, 'r')\n",
    "plt.plot(t, sim.data[voltage][:, 1], 'k')\n",
    "plt.yticks(())\n",
    "plt.axis([0, 1, 0, 2])\n",
    "plt.subplots_adjust(wspace=0.05);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The top graph shows the input signal in green\n",
    "and the filtered output spikes from the two neurons population in blue.\n",
    "The spikes (that are filtered) from the 'on' and 'off' neurons\n",
    "are shown in the bottom graph on the left.\n",
    "On the right are the subthreshold voltages for the neurons."
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
